package com.shoping.common.health;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.actuate.health.SystemHealth;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.scheduling.annotation.Scheduled;

/**
 * 用于获取ApplicationEventPublisher的一个扩展类，ApplicationEventPublisher可以用来发布事件，
 * 结合ApplicationListener来共同使用，下文在介绍ApplicationListener时会详细提到。这个对象也可以通过 spring 注入的方式来获得。
 */
@Slf4j
public class HealthStatusChecker implements ApplicationEventPublisherAware {

    @Autowired
    private HealthEndpoint healthEndpoint;

    private ApplicationEventPublisher applicationEventPublisher;

    private volatile boolean open = false;

    private Status current;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        log.info("-----发布0.ApplicationEventPublisherAware---");
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 定时i检查
     */
    @Scheduled(initialDelay = 3000, fixedDelay = 3000)
    public void check() {
        if (!open) {
            return;
        }
        SystemHealth health = (SystemHealth) healthEndpoint.health();
        Status status = health.getStatus();
        String message = String.valueOf(health.getComponents().get("error"));
        change(status, message);
    }

    private void change(Status status) {
        change(status, null);
    }

    private void change(Status status, String message) {
        if (status.equals(current)) {
            return;
        }

        HealthStatusChangedEvent event = new HealthStatusChangedEvent(this, current, status, message);
        applicationEventPublisher.publishEvent(event);
        this.current = status;
    }

    public void open() {
        Status status = healthEndpoint.health().getStatus();
        open(status);
    }

    public void open(Status status) {
        open = true;
        change(status);
    }

    public void suspend() {
        Status status = healthEndpoint.health().getStatus();
        suspend(status);
    }

    public void suspend(Status status) {
        open = false;
        change(status);
    }

    public boolean isOpen() {
        return open;
    }


}
